package cn.edu.fzu.homemaking.sso.service.impl;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;

import cn.edu.fzu.homemaking.common.TreeVO;
import cn.edu.fzu.homemaking.sso.mapper.ResourceMapper;
import cn.edu.fzu.homemaking.sso.service.ResourceService;
import cn.edu.fzu.homemaking.sso.service.RoleService;
import cn.edu.fzu.homemaking.sso.domain.entity.Resource;
import cn.edu.fzu.homemaking.sso.domain.enums.StatusEnum;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

@Service
public class ResourceServiceImpl implements ResourceService {

    private final ResourceMapper             resourceMapper;

    private final RoleService                roleService;

    private LoadingCache<Long, List<String>> resourceCache = null;

    @Autowired
    public ResourceServiceImpl(ResourceMapper resourceMapper, RoleService roleService) {
        this.resourceMapper = resourceMapper;
        this.roleService = roleService;
        CacheLoader<Long, List<String>> loader = new CacheLoader<Long, List<String>>() {
            @Override
            public List<String> load(Long userId) {
                List<Long> roles = roleService.listRoleIdByUserId(userId);
                List<String> resourceUrls = new LinkedList<>();
                for (Long roleId : roles) {
                    resourceUrls.addAll(resourceMapper.listResourceUrlByRoleId(roleId));
                }
                return resourceUrls;
            }
        };
        resourceCache = CacheBuilder.newBuilder().initialCapacity(1000).build(loader);
    }


    @Override
    public Set<TreeVO<Resource>> list(Long userId, String name, Long pid, StatusEnum status, boolean detail) {
        List<Resource> list = resourceMapper.list(userId, name, pid, status, pid == null);
        Set<TreeVO<Resource>> treeVOSet = new HashSet<>(list.size());
        boolean onlyParent = StringUtils.isNotBlank(name);
        for (Resource resource : list) {
            treeVOSet.add(getTree(userId, resource, onlyParent, detail));
        }
        return treeVOSet;
    }


    @Override
    @Transactional
    public void grant(Long roleId, List<Long> resourceIds) {
        resourceMapper.delRoleResourceByRoleId(roleId);
        if (!CollectionUtils.isEmpty(resourceIds)) {
            resourceMapper.addRoleResource(roleId, resourceIds);
        }
        //刷新所有拥有该角色用户的权限
        List<Long> userIds = roleService.listUserIdByRoleId(roleId);
        for (Long userId : userIds) {
            resourceCache.refresh(userId);
        }
    }


    @Override
    public List<String> listResourceByUserId(Long userId) {
        try {
            return resourceCache.get(userId);
        } catch (ExecutionException e) {
            return new ArrayList<>();
        }
    }


    @Override
    public List<Long> listResourceIdByRoleId(Long roleId) {
        return resourceMapper.listResourceIdByRoleId(roleId);
    }


    private TreeVO<Resource> getTree(Long userId, Resource resource, boolean onlyParent, boolean detail) {
        TreeVO<Resource> treeVO = new TreeVO<>();
        treeVO.setValue(resource);
        if (!onlyParent) {
            List<Resource> children = resourceMapper.list(userId, null, resource.getId(), StatusEnum.NORMAL, false);
            List<TreeVO<Resource>> list = new ArrayList<>(children.size());
            for (Resource child : children) {
                list.add(getTree(userId, child, false, detail));
            }
            treeVO.setChildren(list);
        }
        return treeVO;
    }
}
